from binascii import b2a_hex
from threading import Thread
from time import sleep

from PySide2.QtGui import QIcon
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QListWidgetItem, QMenu, QMessageBox, QTableWidgetItem
from src.ui_opt.ui_debug import DebugWindow
from src.lib.resource_path import resource_path
from src.lib.thread_stop import stop_thread

class AppDebug():
    __m_s_cache_data = ""
    __m_s_data_time = ""
    __m_i_refresh = 0

    def __init__(self, ui, port):
        self.ui = ui
        self.Port = port
        self.MainWindow = self.ui.MainWindow

        '''线程启动'''
        self.pool = ""
        self.pool = Thread(target=self.__uiShow, daemon=True)
        self.pool.start()

        ''' 创建子窗口 '''
        self.Debug_Window = DebugWindow()
        path = resource_path(r'res\LiSun.ico')
        self.Debug_Window.setWindowIcon(QIcon(path))
        # 设置[窗口置顶] 只有[关闭按钮]
        self.Debug_Window.setWindowFlags(Qt.WindowStaysOnTopHint
                                         | Qt.WindowCloseButtonHint)
        # 堵塞父窗口
        self.Debug_Window.setWindowModality(Qt.ApplicationModal)
        self.Debug_Window.text_singal.connect(self.__debugAtSingal)

    # 投递文本到[调试接收框] 会临时等待，然后一并发送
    def uiForwardReceive(self, text):

        if self.__m_i_refresh == 0:
            self.Port.m_s_current_time = self.Port.getCurrentTime()

        self.__m_s_cache_data += text
        self.__m_i_refresh = 1
        # 判断数据是否太快导致不能空闲刷新，故设置了最大长度直接刷新
        location = -1
        offset = 0
        try:
            location = self.__m_s_cache_data.find("OK")
            if location != -1:
                offset = 2
        except Exception:
            location = -1
        try:
            if location == -1 and len(self.__m_s_cache_data) >= 256:
                location = self.__m_s_cache_data.rindex('\n')
                if location != -1:
                    offset = 2
        except Exception:
            return
        if location > 0:
            text = self.__m_s_cache_data[:location + offset]
            self.Port.sendTextToReceive(
                self.Port.Page['DEBUG'].value,
                self.Port.getTimeStrAndText(text))
            self.__m_s_cache_data = self.__m_s_cache_data[location + offset:]
            self.__uiDataAnalysisShow(text)
            location = -1

    # 投递文本到[调试接收框] 不会等待，直接发送
    def uiShowReceive(self, text):
        if self.__m_i_refresh == 0:
            self.Port.m_s_current_time = self.Port.getCurrentTime()
        self.Port.sendTextToReceive(self.Port.Page['DEBUG'].value,
                                    self.Port.getTimeStrAndText(text))

    def uiSendData(self):
        if self.Port.getPortState():
            QMessageBox.critical(self.ui, "Port Error", "请先打开串口！")
            return
        input_s = self.MainWindow.pte_debugSend.toPlainText()
        input_s += '\r\n'
        data = (input_s).encode()
        self.Port.sendMsg(data)
        self.uiShowReceive(input_s)

    def getAtCmd(self, item):
        if item is not None:
            str_s = item.toolTip().split("\n")[0]
            str_s = str_s.strip()
            self.MainWindow.pte_debugSend.setPlainText(str_s)

    def atMenu(self, pos):
        menu = QMenu()
        # 通过坐标计算是否有表项
        hitIndex = self.MainWindow.lvw_debugAT.indexAt(pos).column()
        if hitIndex > -1:
            opt_modif = menu.addAction("修改")
            opt_remove = menu.addAction("删除")
            # 获取item内容
            index = self.MainWindow.lvw_debugAT.currentRow()
            action = menu.exec_(self.MainWindow.lvw_debugAT.mapToGlobal(pos))
            if action == opt_remove:
                ret = QMessageBox.question(self.ui, "提示",
                                           "是否删除该条AT命令?",
                                           QMessageBox.Yes | QMessageBox.No)
                if (ret == QMessageBox.Yes):
                    self.MainWindow.lvw_debugAT.takeItem(index)
            elif action == opt_modif:
                self.__showDebugWindow(index)
        else:
            opt_add = menu.addAction("新增")
            action = menu.exec_(self.MainWindow.lvw_debugAT.mapToGlobal(pos))
            if action == opt_add:
                self.__showDebugWindow(-1)

    def __newListItem(self, text, toolTip):
        # 新建表项
        item = QListWidgetItem()
        item.setText(text)
        item.setToolTip(toolTip)
        return item

    def __showDebugWindow(self, item_index):
        if item_index != -1:
            name = self.MainWindow.lvw_debugAT.item(item_index).text()
            self.Debug_Window.setWindowTitle("修改AT指令")
            self.Debug_Window.ui.le_name.setText(name)
            tip = self.MainWindow.lvw_debugAT.item(item_index).toolTip()
            try:
                list_s = tip.split("\n", 2)
                self.Debug_Window.ui.le_cmd.setText(list_s[0])
                if (len(list_s) >= 3):
                    self.Debug_Window.ui.pte_hint.setPlainText(list_s[2])
            except Exception:
                pass
        else:
            self.Debug_Window.setWindowTitle("新增AT指令")
            self.Debug_Window.ui.le_name.setText("")
            self.Debug_Window.ui.le_cmd.setText("")
            self.Debug_Window.ui.pte_hint.setPlainText("")
        self.Debug_Window.index = item_index
        self.Debug_Window.show()

    def __debugAtSingal(self, index, name, at):
        if index > -1:
            item = self.MainWindow.lvw_debugAT.item(index)
            item.setText(name)
            item.setToolTip(at)
        else:
            item = self.__newListItem(name, at)
            self.MainWindow.lvw_debugAT.addItem(item)

    def __uiShow(self):
        while 1:
            if self.__m_i_refresh == 1:
                self.__m_i_refresh = 2
            elif (self.__m_i_refresh == 2 and self.__m_s_cache_data != ""
                  and self.__m_s_cache_data != " "
                  and self.__m_s_cache_data != "\n"
                  and self.__m_s_cache_data != "\r\n"):
                self.Port.sendTextToReceive(
                    self.Port.Page['DEBUG'].value,
                    self.Port.getTimeStrAndText(self.__m_s_cache_data))
                self.__m_s_cache_data = ""
                self.__m_i_refresh = 0
            sleep(0.02)

    # 列表全选
    def uiLoopAtFull(self):
        i_row_count = self.MainWindow.tbw_loopDebugAT.rowCount()
        for i in range(i_row_count):
            self.MainWindow.tbw_loopDebugAT.item(i, 0).setCheckState(Qt.Checked)

    # 列表全不选
    def uiLoopAtNop(self):
        i_row_count = self.MainWindow.tbw_loopDebugAT.rowCount()
        for i in range(i_row_count):
            self.MainWindow.tbw_loopDebugAT.item(i, 0).setCheckState(Qt.Unchecked)

    def __controlSwitch(self, state):
        self.MainWindow.le_loopDebugSendNum.setEnabled(state)
        self.MainWindow.tbw_loopDebugAT.setEnabled(state)
        self.MainWindow.btn_loopDebugFull.setEnabled(state)
        self.MainWindow.btn_loopDebugNop.setEnabled(state)
        self.MainWindow.btn_debugSend.setEnabled(state)
        self.MainWindow.brn_upStartUpgrade.setEnabled(state)

    def uiLoopAtAddLine(self):
        row = self.MainWindow.tbw_loopDebugAT.rowCount()
        self.MainWindow.tbw_loopDebugAT.insertRow(int(row))
        newItem = QTableWidgetItem()
        newItem.setCheckState(Qt.Unchecked)
        self.MainWindow.tbw_loopDebugAT.setItem(row, 0, newItem)
        newItem = QTableWidgetItem()
        self.MainWindow.tbw_loopDebugAT.setItem(row, 1, newItem)

    def uiLoopAtDelLine(self):
        ret = QMessageBox.question(self.ui, "提示", "是否删除该本行?",
                                   QMessageBox.Yes | QMessageBox.No)
        if (ret == QMessageBox.Yes):
            index = self.MainWindow.tbw_loopDebugAT.currentRow()
            self.MainWindow.tbw_loopDebugAT.removeRow(index)

    def uiLoopAtMenu(self, pos):
        menu = QMenu()
        # 通过坐标计算是否有表项
        hitIndex = self.MainWindow.tbw_loopDebugAT.indexAt(pos).column()
        if hitIndex > -1:
            opt_remove = menu.addAction("删除本行")
            # 获取item内容
            action = menu.exec_(
                self.MainWindow.tbw_loopDebugAT.mapToGlobal(pos))
            if action == opt_remove:
                self.uiLoopAtDelLine()
        else:
            opt_add = menu.addAction("新增一行")
            action = menu.exec_(
                self.MainWindow.tbw_loopDebugAT.mapToGlobal(pos))
            if action == opt_add:
                self.uiLoopAtAddLine()

    def uiLoopStart(self):
        i_row_count = self.MainWindow.tbw_loopDebugAT.rowCount()
        i = 0
        self.m_l_loop_data = []
        if (i_row_count < 1):
            return
        for i in range(i_row_count):
            if (self.MainWindow.tbw_loopDebugAT.item(i, 0).checkState()):
                self.m_l_loop_data.append(
                    self.MainWindow.tbw_loopDebugAT.item(i, 0).text() + "|" +
                    self.MainWindow.tbw_loopDebugAT.item(i, 1).text())
        print(self.m_l_loop_data)
        self.m_i_loop_send_num = int(
            self.MainWindow.le_loopDebugSendNum.text())
        # 启动线程
        '''线程启动'''
        self.pool = ""
        self.pool = Thread(target=self.task_loop_send, daemon=True)
        self.pool.start()
        self.MainWindow.btn_loopDebugStart.setText("停止循环")
        self.__controlSwitch(False)

    def uiLoopStop(self):
        # 设置标志位
        self.MainWindow.btn_loopDebugStart.setText("开始循环")
        self.__controlSwitch(True)

    def uiLoopSwitch(self):
        if (self.Port.getPortState()):
            QMessageBox.critical(self.ui, "Port Error", "请先打开串口！")
            return
        if (self.MainWindow.btn_loopDebugStart.text() == "开始循环"):
            self.uiLoopStart()
        else:
            '''线程终止Kill'''
            stop_thread(self.pool)
            self.uiLoopStop()

    def task_loop_send(self):
        lf = True
        list_index = 0
        num = len(self.m_l_loop_data)
        cmd_list = []
        delay_list = []
        for i in range(0, num):
            at_s, delay_s = self.m_l_loop_data[i].split("|", 1)
            if (lf):
                at_s += '\r\n'
            try:
                delay_list.append(int(delay_s))
            except Exception:
                delay_list.append(1000)
            cmd_list.append(at_s)

        while 1:
            if (self.Port.getPortState()):
                self.uiLoopStop()
                return
            if (self.m_i_loop_send_num != 0):
                if (list_index >= num):
                    list_index = 0
                    if (self.m_i_loop_send_num != -1):
                        self.m_i_loop_send_num = self.m_i_loop_send_num - 1
                    if (self.m_i_loop_send_num == 0):
                        list_index = 0
                        self.uiLoopStop()
                        return
                if (num > 0 and (list_index < num)):
                    self.Port.sendMsg((cmd_list[list_index]).encode())
                    self.uiShowReceive("(Tx) " + cmd_list[list_index])
                    sleep(delay_list[list_index] / 1000)
                    list_index += 1
            else:
                self.uiLoopStop()

    def __uiDataAnalysisShow(self, data):
        if data[:2].find("\r\n") != -1:
            data = data[2:]
        if data.find("Ver: ") == 0:
            data = data[data.find("Ver: "):]
            buff = data.split("\r\n")
            print(buff)
            self.MainWindow.lbl_lampInfoFirmwareVer.setText(buff[0].replace("Ver: ", ""))
            self.MainWindow.lbl_lampInfoProductName.setText(buff[1].replace("Pro: ", ""))
            self.MainWindow.lbl_lampInfoFirmwareDate.setText(buff[2].replace("Date: ", ""))
        elif data.find("POWERINFO=") == 0:
            data = data[data.find("POWERINFO=") + len("POWERINFO="):]
            data = data.replace("\r\nAT^OK", "")
            buff = data.split(",")
            print(buff)
            self.MainWindow.lbl_lampInfoBatSoc.setText(buff[3])
            self.MainWindow.lbl_lampInfoBatVol.setText(buff[4])
            self.MainWindow.lbl_lampInfoBatFullVol.setText(buff[5])
            self.MainWindow.lbl_lampInfoBatState.setText(buff[2])
        elif data.find("SYSINFO=") == 0:
            data = data[data.find("SYSINFO=") + len("SYSINFO="):]
            data = data.replace("\r\nAT^OK", "")
            data = data.replace("\r\n", "")
            buff = data.split(",")
            print(buff)
            self.MainWindow.lbl_lampInfoState.setText(buff[0])
            self.MainWindow.lbl_lampInfoMode.setText(buff[1])
            self.MainWindow.lbl_lampInfoGrade.setText(buff[2])
            self.MainWindow.lbl_lampInfoLock.setText(buff[3])
            self.MainWindow.lbl_lampInfoDayNight.setText(buff[4])
        elif data.find("LAMPCFG=") == 0:
            data = data[data.find("LAMPCFG=") + len("LAMPCFG="):]
            data = data.replace("\r\nAT^OK", "")
            data = data.replace("\r\n", "")
            buff = data.split("|")
            print(buff)
            self.Port.lampCfg_signal.emit(buff)
        elif data.find("LAMPTEMPERATURE=") == 0:
            data = data[data.find("LAMPTEMPERATURE=") + len("LAMPTEMPERATURE="):]
            data = data.replace("\r\nAT^OK", "")
            data = data.replace("\r\n", "")
            self.MainWindow.lbl_lampInfoTemp.setText(data)
        elif data.find("LAMPPWMOUT=") == 0:
            data = data[data.find("LAMPPWMOUT=") + len("LAMPPWMOUT="):]
            data = data.replace("\r\nAT^OK", "")
            data = data.replace("\r\n", "")
            self.MainWindow.lbl_lampInfoLuminPct.setText(data)
